package com.kinyx.framework.constraints;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.List;

import javax.util.XArrayList;
import javax.validation.Constraint;
import javax.validation.ConstraintValidatorContext;
import javax.validation.Payload;

import com.kinyx.framework.constraints.IDCard.Validator;
import com.kinyx.framework.file.KPropertiesReader;
import com.kinyx.framework.utils.KListUtils;
import com.kinyx.framework.utils.KMatcherUtils;

/**
 * 身份证号验证注解
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = Validator.class)
public @interface IDCard {

	public static final String REGEX = KPropertiesReader.getStringValue(Configs.PROPERTIES, IDCard.class.getSimpleName(),
			// 地区编码
			String.format("(%s)[0-9]{4}", KListUtils.join(new XArrayList<String>()
					// 华北
					.xAdd("11")// 北京
					.xAdd("12")// 天津
					.xAdd("13")// 河北
					.xAdd("14")// 山西
					.xAdd("15")// 内蒙古
					// 东北
					.xAdd("21")// 辽宁
					.xAdd("22")// 吉林
					.xAdd("23")// 黑龙江
					// 华东
					.xAdd("31")// 上海
					.xAdd("32")// 江苏
					.xAdd("33")// 浙江
					.xAdd("34")// 安徽
					.xAdd("35")// 福建
					.xAdd("36")// 江西
					.xAdd("37")// 山东
					// 华中
					.xAdd("41")// 河南
					.xAdd("42")// 湖北
					.xAdd("43")// 湖南
					// 华南
					.xAdd("44")// 广东
					.xAdd("45")// 广西
					.xAdd("46")// 海南
					// 西南
					.xAdd("50")// 重庆
					.xAdd("51")// 四川
					.xAdd("52")// 贵州
					.xAdd("53")// 云南
					.xAdd("54")// 西藏
					// 西北
					.xAdd("61")// 山西
					.xAdd("62")// 甘肃
					.xAdd("63")// 青海
					.xAdd("64")// 宁夏
					.xAdd("65")// 新疆
					// 特别
					.xAdd("71")// 台湾
					.xAdd("81")// 香港
					.xAdd("82")// 澳门
					, "|", (str, idx) -> { return "(" + str + ")"; }))

					// 年
					+ "((19|20)[0-9]{2}){1}"
					// 月
					+ "((0[1-9]{1})|(1[0-2]{1})){1}"
					// 日
					+ "((0[1-9]{1})|([12]{1}[0-9]{1})|(3[0-1]{1})){1}"
					// 顺序吗
					+ "[0-9]{3}"
					// 校验码
					+ "[0-9xX]{1}");

	String message() default "";

	Class<?>[] groups() default {};

	Class<? extends Payload>[] payload() default {};

	class Validator extends RegexMatchValidator<IDCard> {

		@Override
		protected boolean validate(final String value, final ConstraintValidatorContext context) {
			final boolean flag = KMatcherUtils.matches(value, REGEX);
			if (!flag) { return false; }
			return Validator.check(value.toString());
		}

		private static final List<Integer> coefficients = new XArrayList<Integer>().xAdd(7).xAdd(9).xAdd(10).xAdd(5).xAdd(8).xAdd(4).xAdd(2).xAdd(1).xAdd(6).xAdd(3).xAdd(7).xAdd(9).xAdd(10).xAdd(5).xAdd(8).xAdd(4).xAdd(2);
		private static final List<String> checkCodes = new XArrayList<String>().xAdd("1").xAdd("0").xAdd("X").xAdd("9").xAdd("8").xAdd("7").xAdd("6").xAdd("5").xAdd("4").xAdd("3").xAdd("2");

		static boolean check(final String value) {
			int sum = 0;
			for (int i = 0; i < coefficients.size(); i++) {
				sum += Integer.parseInt(String.valueOf(value.charAt(i))) * coefficients.get(i);
			}
			final String checkCode = String.valueOf(value.charAt(17));
			final int remainder = sum % 11;
			return checkCodes.get(remainder).equals(checkCode);
		}

	}

}
